﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Soundelle;
using Soundelle.Oscillator;

namespace Soundelle.Oscillator.GUI
{
    public partial class ControlDeviceTree : UserControl
    {
        private Oscillator.BaseDevice OscillatorDevice = null;
        private Dictionary<Guid, Oscillator.BaseDevice> OscillatorDictionary = new Dictionary<Guid, Oscillator.BaseDevice>();

        private Dictionary<Guid, UserControl> GuiDictionary = new Dictionary<Guid, UserControl>();

        public event EventHandler DeviceSelected;
        public event EventHandler DeviceChanged;
        public event EventHandler DeviceTreeChanged;


        private Oscillator.BaseDevice _SelectedDevice = null;
        public Oscillator.BaseDevice SelectedDevice
        {
            get { return _SelectedDevice; }
        }

        public ControlDeviceTree()
        {
            InitializeComponent();
            splitContainer1.Dock = DockStyle.Fill;
            groupDeviceTree.Dock = DockStyle.Fill;
            treeDevices.Dock = DockStyle.Fill;

            treeDevices.HideSelection = false;
        }

        public void AttachDevice(ref Oscillator.BaseDevice Device)
        {
            OscillatorDevice = Device;

            UpdateTreeView();
        }

        public void DettachDevice()
        {
            OscillatorDevice = null;
        }

        public void UpdateTreeView()
        {
            OscillatorDictionary.Clear();
            OscillatorDevice.GetDeviceDictionary(ref OscillatorDictionary);

            UpdateGuiDictionary();

            treeDevices.Nodes.Clear();

            TreeNode rootNode = treeDevices.Nodes.Add(OscillatorDevice.GUID.ToString(), OscillatorDevice.GetType().ToString());
            //rootNode.ContextMenuStrip = contextMenu;
            UpdateTreeChilds(ref OscillatorDevice, ref rootNode);

            treeDevices.ExpandAll();
            treeDevices.SelectedNode = treeDevices.Nodes[0];
        }

        private void UpdateGuiDictionary()
        {
            for (int i=0; i<OscillatorDictionary.Count; ++i)
            {
                System.Guid id = OscillatorDictionary.ElementAt<KeyValuePair<Guid, Oscillator.BaseDevice>>(i).Key;
                Soundelle.Oscillator.BaseDevice dev = OscillatorDictionary.ElementAt<KeyValuePair<Guid, Oscillator.BaseDevice>>(i).Value;

                if (! GuiDictionary.ContainsKey(id))
                {
                    UserControl gui=null;

                    if (dev is Oscillator.StreamOut.BaseFileWriter)
                    {
                        ControlDevice ctrl = new ControlDevice();
                        ctrl.AttachDevice(ref dev);
                        gui = (UserControl)ctrl;
                    }
                    else if (dev is Oscillator.StreamOut.BasePlayer)
                    {
                        ControlDevice ctrl = new ControlDevice();
                        ctrl.AttachDevice(ref dev);
                        gui = (UserControl)ctrl;
                    }
                    else if (dev is Oscillator.BaseDevice)
                    {
                        ControlDevice ctrl = new ControlDevice();
                        ctrl.AttachDevice(ref dev);
                        gui = (UserControl)ctrl;
                    }
                    else 
                    {
                        gui = null;
                    }

                    if (gui != null)
                    {
                        gui.Size = new System.Drawing.Size(160, 160);
                        gui.Visible = false;
                        this.splitContainer1.Panel2.Controls.Add(gui);
                        gui.Dock = DockStyle.Fill;
                        
                        GuiDictionary.Add(id, gui);
                    }
                }
            }
        }

        private void RemoveDevice(ref Oscillator.BaseDevice Device, bool IsRemoveTree)
        {
            // it also has to remove the gui from guidictionary (not implemented yet)

            Oscillator.BaseDevice Parent = GetParent(ref Device);

            if (Parent == null)
                return;

            if (IsRemoveTree)
            {
                Parent.Devices.Remove(Device);
            }
            else
            {
                if (Device.Devices.Count > 0)
                {
                    for (int i = 0; i < Device.Devices.Count; ++i)
                    {
                        Oscillator.BaseDevice child = Device.Devices[i];
                        Parent.Add(ref child);
                    }
                }
                Parent.Devices.Remove(Device);
            }
        }

        private Oscillator.BaseDevice GetParent(ref Oscillator.BaseDevice Device)
        {
            Oscillator.BaseDevice Parent = null;

            if (OscillatorDevice != null)
            {
                if (OscillatorDevice.GUID != Device.GUID)
                {
                    for (int i = 0; i < OscillatorDictionary.Count; ++i)
                    {
                        Oscillator.BaseDevice dev = OscillatorDictionary.ElementAt<KeyValuePair<Guid, Oscillator.BaseDevice>>(i).Value;
                        foreach (Oscillator.BaseDevice child in dev.Devices)
                        {
                            if (child.GUID == Device.GUID)
                                return dev;
                        }
                    }
                }
            }

            return Parent;
        }

        private void UpdateTreeChilds(ref Oscillator.BaseDevice Device, ref TreeNode Node)
        {
            if (Device == null)
                return;

            foreach (Oscillator.BaseDevice cd in Device.Devices)
            {
                Oscillator.BaseDevice ChildDevice = cd;
                TreeNode ChildNode = Node.Nodes.Add(ChildDevice.GUID.ToString(), ChildDevice.GetType().ToString());
                //ChildNode.ContextMenuStrip = contextMenu;
                UpdateTreeChilds(ref ChildDevice, ref ChildNode);
            }
        }

        private void treeDevices_AfterSelect(object sender, TreeViewEventArgs e)
        {
            Oscillator.BaseDevice dev;
            OscillatorDictionary.TryGetValue(Guid.Parse(treeDevices.SelectedNode.Name), out dev);
            if (dev != null)
            {
                UserControl ctrl;
                GuiDictionary.TryGetValue(dev.GUID, out ctrl);
                ctrl.Visible = true;
                ctrl.BringToFront();

                bool changed = false;
                if (_SelectedDevice != dev)
                    changed = true;

                _SelectedDevice = dev;

                if (DeviceSelected != null)
                    DeviceSelected(this, EventArgs.Empty);
                if (DeviceChanged != null && changed)
                    DeviceChanged(this, EventArgs.Empty);
            }
        }

        private void treeDevices_MouseUp(object sender, MouseEventArgs e)
        {
            this.treeDevices.Focus();
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                TreeNode node = this.treeDevices.GetNodeAt(e.X, e.Y);
                if (node != null)
                {
                    this.treeDevices.SelectedNode = node;
                    contextMenu.Show(treeDevices, e.Location);
                }
            }
        }

        private void treeDevices_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Insert:
                    if (SelectedDevice != null)
                    {
                        Oscillator.BaseDevice dev = new Oscillator.GeneratorMulti();
                        SelectedDevice.Add(ref dev);
                        UpdateTreeView();

                        if (DeviceTreeChanged != null)
                            DeviceTreeChanged(this, EventArgs.Empty);
                    }
                    break;

                case Keys.Delete:
                    if (SelectedDevice != null)
                    {
                        RemoveDevice(ref _SelectedDevice, e.Shift);
                        UpdateTreeView();

                        if (DeviceTreeChanged != null)
                            DeviceTreeChanged(this, EventArgs.Empty);
                    }
                    break;

                default:
                    break;
            }
        }

        #region "Remove Device"

        private void MenuRemoveDeviceTree_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev;
                OscillatorDictionary.TryGetValue(Guid.Parse(treeDevices.SelectedNode.Name), out dev);

                if (dev != null)
                {
                    RemoveDevice(ref dev, true);
                    UpdateTreeView();

                    if (DeviceTreeChanged != null)
                        DeviceTreeChanged(this, EventArgs.Empty);
                }
            }
        }

        private void MenuRemoveDevice_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev;
                OscillatorDictionary.TryGetValue(Guid.Parse(treeDevices.SelectedNode.Name), out dev);

                if (dev != null)
                {
                    RemoveDevice(ref dev, false);
                    UpdateTreeView();

                    if (DeviceTreeChanged != null)
                        DeviceTreeChanged(this, EventArgs.Empty);
                }
            }
        }

        private void MenuRemoveChildDevices_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev;
                OscillatorDictionary.TryGetValue(Guid.Parse(treeDevices.SelectedNode.Name), out dev);

                if (dev != null)
                {
                    if (dev.Devices.Count > 0)
                    {
                        for (int i = dev.Devices.Count - 1; i >= 0; --i)
                        {
                            Oscillator.BaseDevice child = dev.Devices[i];
                            RemoveDevice(ref child, true);
                        }
                        UpdateTreeView();

                        if (DeviceTreeChanged != null)
                            DeviceTreeChanged(this, EventArgs.Empty);
                    }
                }
            }
        }

        #endregion

        #region "Replace Base Device"

        private void replaceDevice(Oscillator.BaseDevice device)
        {
            foreach (Oscillator.BaseDevice dev in OscillatorDevice.Devices)
            {
                Oscillator.BaseDevice d = dev;
                device.Add(ref d);

                OscillatorDevice = null;
                OscillatorDevice = device;

                UpdateTreeView();
            }
        }

        private void MenuReplaceBaseDeviceGeneral_Click(object sender, EventArgs e)
        {
            Oscillator.BaseDevice device = new BaseDevice();
            replaceDevice(device);
        }

        private void MenuReplaceFileWriterWav_Click(object sender, EventArgs e)
        {
            Oscillator.StreamOut.FileWriterWav device = new StreamOut.FileWriterWav();
            replaceDevice(device);
        }

        private void MenuReplaceFileWriterUffAsc_Click(object sender, EventArgs e)
        {
            Oscillator.StreamOut.FileWriterUffAsc device = new StreamOut.FileWriterUffAsc();
            replaceDevice(device);
        }

        private void MenuReplacePlayerWav_Click(object sender, EventArgs e)
        {
            Oscillator.StreamOut.PlayerWav device = new StreamOut.PlayerWav();
            replaceDevice(device);
        }

        #endregion


        private void MenuInsertGeneratorMulti_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev = new Oscillator.GeneratorMulti();
                SelectedDevice.Add(ref dev);
                UpdateTreeView();

                if (DeviceTreeChanged != null)
                    DeviceTreeChanged(this, EventArgs.Empty);
            }
        }

        private void MenuInsertGeneratorSine_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev = new Oscillator.GeneratorSine();
                SelectedDevice.Add(ref dev);
                UpdateTreeView();

                if (DeviceTreeChanged != null)
                    DeviceTreeChanged(this, EventArgs.Empty);
            }
        }

        private void MenuInsertGeneratorSquare_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev = new Oscillator.GeneratorSquare();
                SelectedDevice.Add(ref dev);
                UpdateTreeView();

                if (DeviceTreeChanged != null)
                    DeviceTreeChanged(this, EventArgs.Empty);
            }
        }

        private void MenuInsertGeneratorRandom_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev = new Oscillator.GeneratorRandom();
                SelectedDevice.Add(ref dev);
                UpdateTreeView();

                if (DeviceTreeChanged != null)
                    DeviceTreeChanged(this, EventArgs.Empty);
            }
        }

        private void MenuInsertFilterRMS_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev = new Oscillator.FilterAverage();
                SelectedDevice.Add(ref dev);
                UpdateTreeView();

                if (DeviceTreeChanged != null)
                    DeviceTreeChanged(this, EventArgs.Empty);
            }
        }

        private void MenuInsertCalculatorTachometer_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev = new Oscillator.CalculatorTachometer();
                SelectedDevice.Add(ref dev);
                UpdateTreeView();

                if (DeviceTreeChanged != null)
                    DeviceTreeChanged(this, EventArgs.Empty);
            }
        }

        private void MenuInsertCalculatorCalculus_Click(object sender, EventArgs e)
        {
            if (SelectedDevice != null)
            {
                Oscillator.BaseDevice dev = new Oscillator.CalculatorCalculus();
                SelectedDevice.Add(ref dev);
                UpdateTreeView();

                if (DeviceTreeChanged != null)
                    DeviceTreeChanged(this, EventArgs.Empty);
            }
        }



    }
}
